
已经看到了模板参数在使用字符串字面值和数组时不同的效果:

\begin{itemize}
\item 
按值调用会衰变，使其成为指向元素类型的指针。

\item 
引用调用都不会衰变，因此参数成为仍然是数组。
\end{itemize}

两者都可能是可工作的，也可能是不工作的。当数组衰变为指针时，将失去区分处理指向元素的指针和处理传递的数组的能力。另一方面，处理可能传递字符串字面值的参数时，因为不同大小的字符串字面值有不同的类型，所以不衰变可能有问题。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void foo (T const& arg1, T const& arg2)
{
	...
}

foo("hi", "guy"); // ERROR
\end{lstlisting}

这里，foo("hi"，"guy")无法进行编译，因为"hi"的类型是char const[3]，而"guy"的类型是char const[4]，但模板要求它们具有相同的类型T。只有当字符串字面值具有相同的长度时，这样的代码才能编译。出于这个原因，强烈建议在测试用例中使用不同长度的字符串字面值。

通过声明函数模板foo()来通过值传递参数:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void foo (T arg1, T arg2)
{
	...
}

foo("hi", "guy"); // compiles, but ...
\end{lstlisting}

但是，这并不意味着所有的问题都消失了。更糟糕的是，编译时问题可能变成了运行时问题。考虑下面的代码，使用operator==比较传递的参数:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void foo (T arg1, T arg2)
{
	if (arg1 == arg2) { // OOPS: compares addresses of passed arrays
		...
	}
}

foo("hi", "guy"); // compiles, but ...
\end{lstlisting}

因为模板还必须处理来自已衰变的字符串字面量参数(例如，通过value调用的函数或赋值给使用auto声明的对象)，所以编译器必须知道应该将传递的字符指针解释为字符串。

许多情况下衰变是有用的，特别是用于检查两个对象(都作为参数传递，或者一个作为传递参数，另一个作为期待参数)是否具有或转换为相同的类型。典型的用法是完美转发，但想使用完美转发，必须将参数声明为转发引用。这种情况下，可以使用类型特征std::decay<>()显式地衰变参数。具体的例子请参阅第120页7.6节中的std::make\_pair()。

其他类型特征有时也隐式衰变，例如std::common\_type<>，会产生两个传递参数类型的通用类型(参见章节1.3.3和章节D.5)。

\subsubsubsection{7.4.1\hspace{0.2cm}字符串字面值和数组的特殊实现}

可能需要根据传递的是指针，还是数组来区分实现。当然，这要求传递的数组没有衰变。

要区分这些情况，必须检测是否传递了数组。基本上有两种选择:

\begin{itemize}
\item 
可以声明模板参数，使其只对数组有效:

\begin{lstlisting}[style=styleCXX]
template<typename T, std::size_t L1, std::size_t L2>
void foo(T (&arg1)[L1], T (&arg2)[L2])
{
	T* pa = arg1; // decay arg1
	T* pb = arg2; // decay arg2
	if (compareArrays(pa, L1, pb, L2)) {
		...
	}
}
\end{lstlisting}

这里，arg1和arg2必须是数组，具有相同的元素类型T，但L1和L2大小不同。但请注意，可能需要多个实现来支持数组(参见第5.4节)。

\item 
可以使用类型特征来检测是否传递了数组(或指针):

\begin{lstlisting}[style=styleCXX]
template<typename T,
		 typename = std::enable_if_t<std::is_array_v<T>>>
void foo (T&& arg1, T&& arg2)
{
	...
}
\end{lstlisting}
\end{itemize}

由于这些属于特殊的处理方式，而常用处理数组方式就是使用不同的函数名。当然，更好的方法是确定模板的调用者使用std::vector或std::array。只要字符串字面值是数组，就必须考虑这种情况。


















